package com.ta.gulimall.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ta.gulimall.common.view.to.SpuBoundTo;
import com.ta.gulimall.common.view.to.UpSpuInfoTo;
import com.ta.gulimall.common.utils.system.R;
import com.ta.gulimall.product.feign.CouponFeignService;
import com.ta.gulimall.product.feign.ElasticsearchFeignService;
import com.ta.gulimall.product.feign.WareFeignService;
import com.ta.gulimall.product.service.*;
import com.ta.gulimall.product.view.entity.*;
import com.ta.gulimall.product.view.pto.SpuDto;
import com.ta.gulimall.product.view.vo.SpuVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ta.gulimall.common.utils.system.PageUtils;
import com.ta.gulimall.common.utils.system.Query;

import com.ta.gulimall.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
    @Autowired
    SpuInfoDescService spuInfoDescService;
    @Autowired
    SpuImagesService spuImagesService;
    @Autowired
    ProductAttrValueService productAttrValueService;
    @Autowired
    SkuInfoService skuInfoService;
    @Autowired
    CouponFeignService couponFeignService;
    @Autowired
    AttrService attrService;
    @Autowired
    CategoryService categoryService;
    @Autowired
    BrandService brandService;
    @Autowired
    WareFeignService wareFeignService;
    @Autowired
    ElasticsearchFeignService elasticsearchFeignService;


    @Override
    @Transactional
    public void saveSpuInfo(SpuVo spuVo) {

        SpuInfoEntity spuInfo = BeanUtil.copyProperties(spuVo, SpuInfoEntity.class).setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now());

        this.save(spuInfo);
        SpuDto spuDto = SpuDto.builder().spuId(spuInfo.getId()).brandId(spuVo.getBrandId()).catalogId(spuInfo.getCatalogId()).build();

        spuInfoDescService.saveSpuInfoDesc(spuDto, spuVo.getDecript());

        spuImagesService.saveSpuImages(spuDto, spuVo.getImages());

        productAttrValueService.saveProductAttrs(spuDto, spuVo.getBaseAttrs());

        skuInfoService.saveSkuInfo(spuDto, spuVo.getSkus());

        SpuBoundTo spuBoundTo = BeanUtil.copyProperties(spuVo.getBounds(), SpuBoundTo.class).setSpuId(spuDto.getSpuId());

        couponFeignService.saveSpuBound(spuBoundTo);

    }

    @Override
    public PageUtils pageSpuinfos(Map<String, Object> params) {
        String key = (String) params.get("key");
        String catelogId = (String) params.get("catelogId");
        String brandId = (String) params.get("brandId");

        LambdaQueryWrapper<SpuInfoEntity> wrapper = new LambdaQueryWrapper<SpuInfoEntity>()
                .eq(StrUtil.isNotBlank(catelogId) && !"0".equals(catelogId), SpuInfoEntity::getCatalogId, catelogId)
                .eq(StrUtil.isNotBlank(brandId) && !"0".equals(brandId), SpuInfoEntity::getBrandId, brandId)
                .eq(StrUtil.isNotBlank((String)params.get("status")), SpuInfoEntity::getPublishStatus, params.get("status"))
                .and(StrUtil.isNotBlank(key), eq ->  eq.eq(SpuInfoEntity::getId, key).or().like(SpuInfoEntity::getSpuName, key));
        IPage<SpuInfoEntity> page = this.page(new Query<SpuInfoEntity>().getPage(params), wrapper);

        return new PageUtils(page);
    }

    @Override
    public void upSpuInfo(Long spuId) {
        List<SkuInfoEntity> skuList = skuInfoService.listSkuInfo(spuId);

        List<Long> catalogIds = skuList.stream().map(SkuInfoEntity::getCatalogId).collect(Collectors.toList());
        Map<Long, CategoryEntity> categoryEntityMap = categoryService.mapCategory(catalogIds);

        List<Long> brandIds = skuList.stream().map(SkuInfoEntity::getBrandId).collect(Collectors.toList());
        Map<Long, BrandEntity> brandEntityMap = brandService.brandEntityMap(brandIds);

        List<ProductAttrValueEntity> productAttrs = productAttrValueService.listSpuAttr(spuId);
        List<Long> attrIds = productAttrs.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());
        List<Long> finalAttrIds  = attrService.listAttrs(attrIds);
        List<UpSpuInfoTo.Attr> attrList = productAttrs.stream().filter(f -> finalAttrIds.remove(f.getAttrId()))
                .map(m -> BeanUtil.copyProperties(m, UpSpuInfoTo.Attr.class)).collect(Collectors.toList());

        List<Long> skuIds = skuList.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        Map<Long, Long> wareMap = wareFeignService.listSkuWare(skuIds).getData(new TypeReference<Map<Long, Long>>() {});

        List<UpSpuInfoTo> upSpuInfoTos = skuList.stream().map(m -> {
            return BeanUtil.copyProperties(m, UpSpuInfoTo.class)
                    .setCatalogName(categoryEntityMap.get(m.getCatalogId()).getName())
                    .setBrandName(brandEntityMap.get(m.getBrandId()).getName())
                    .setBrandImg(brandEntityMap.get(m.getBrandId()).getLogo())
                    .setAttrs(attrList)
                    .setHasStock(Optional.ofNullable(wareMap.get(m.getSkuId())).orElse(0L) > 0);
        }).collect(Collectors.toList());

        R productSave = elasticsearchFeignService.productSave(upSpuInfoTos);

        updateById(new SpuInfoEntity().setId(spuId).setPublishStatus(Boolean.TRUE));

    }

    @Override
    public Map<Long, SpuInfoEntity> listSpuInfoBySkuIds(List<Long> skuIds) {
        Map<Long, Long> spuIdMap = skuInfoService.listSpuIdBySkuIds(skuIds);
        Map<Long, SpuInfoEntity> entityMap = baseMapper.listSkuInfoByIds(spuIdMap.values());
        return spuIdMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, v -> entityMap.get(v.getValue())));
    }


}